/***************************************************************************
 *   KShootout - online shootout card game.                                *
 *   Copyright (C) 2008, 2009  MacJariel                                   *
 *                                                                         *
 *   KShootout is free software: you can redistribute it and/or modify     *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   KShootout is distributed in the hope that it will be useful,          *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with KShootout.  If not, see <http://www.gnu.org/licenses/>.    *
 ***************************************************************************/
#include "gameeventparser.h"
#include "parser/gamestructparser.h"
#include "gametypes.h"
#include "util.h"
#include "stringconverter.h"

#include "debug/debugblock.h"

#include <QMapIterator>

/*[[[cog
import cog
from gameeventdefs import *
]]]
[[[end]]]*/

/* static */
void GameEventParser::write(QXmlStreamWriter* w, GameEventDataPtr e)
{
    DEBUG_BLOCK;
    w->writeStartElement("game-event");
    w->writeAttribute("game-id", toString(e->gameId));
    w->writeAttribute("type", GameEventData::typeToString(e->type));
    if (e->playerId != 0) {
        w->writeAttribute("player-id", toString(e->playerId));
    }
    if (e->targetPlayerId != 0) {
        w->writeAttribute("target-player-id", toString(e->targetPlayerId));
    }
    if (e->type == GameEventData::CheckDeckType) {
        w->writeAttribute("success", toString(e->success));
    }
    if (e->useAbility) {
        w->writeAttribute("use-ability", toString(e->useAbility));
    }
    QMapIterator<GameEventData::CardMeaning, CardData> it(e->cards);
    while (it.hasNext()) {
        it.next();
        w->writeStartElement(GameEventData::cardMeaningToString(it.key()));
        GameStructParser::write(w, it.value());
        w->writeEndElement();
    }
    foreach (GameEventCmdDataPtr CmdData, e->cmds) {
        writeCmdData(w, CmdData);
    }
    w->writeEndElement();
}

/* static */
GameEventDataPtr GameEventParser::read(XmlNode* node)
{
    DEBUG_BLOCK;
    GameEventDataPtr e(new GameEventData());
    if (node->name() != "game-event") {
        return GameEventDataPtr();
    }
    fromString(node->attribute("game-id"), e->gameId);
    e->type             = GameEventData::stringToType(node->attribute("type"));
    fromString(node->attribute("player-id"), e->playerId);
    fromString(node->attribute("target-player-id"), e->targetPlayerId);
    fromString(node->attribute("success"), e->success);
    fromString(node->attribute("use-ability"), e->useAbility);
    GameEventData::CardMeaning cardMeaning;
    foreach (XmlNode* CmdData, node->getChildren()) {
        cardMeaning = GameEventData::stringToCardMeaning(CmdData->name());
         if (cardMeaning != GameEventData::NoCard) {
             GameStructParser::read(CmdData, e->cards[cardMeaning]);
         } else {
             e->cmds.append(readCmdData(CmdData));
         }
    }
    return e;
}



/* static */
void GameEventParser::writeCmdData(QXmlStreamWriter* w, const GameEventCmdDataPtr& e)
{

    switch(e->t()) {
    /*[[[cog
    for gec in GameEventCmds:
        cog.outl("case GameEventCmdData::%(gameEventCmdType)s: write%(gameEventCmdName)s(w, e.staticCast<%(structName)s>());" % gec)
        cog.outl("    break;")
    ]]]*/
    case GameEventCmdData::MoveCardType: writeMoveCard(w, e.staticCast<MoveCardCmdData>());
        break;
    case GameEventCmdData::UpdatePlayerType: writeUpdatePlayer(w, e.staticCast<UpdatePlayerCmdData>());
        break;
    case GameEventCmdData::UpdateGameContextType: writeUpdateGameContext(w, e.staticCast<UpdateGameContextCmdData>());
        break;
    case GameEventCmdData::SetPlayersType: writeSetPlayers(w, e.staticCast<SetPlayersCmdData>());
        break;
    //[[[end]]]
    }
}

/* static */
GameEventCmdDataPtr GameEventParser::readCmdData(XmlNode* node)
{
    /*[[[cog
    for gec in GameEventCmds:
        cog.outl("if (node->name() == %(elemName)s) {" % gec)
        cog.outl("    return read%(gameEventCmdName)s(node);" % gec)
        cog.outl("}")
    ]]]*/
    if (node->name() == "move-card") {
        return readMoveCard(node);
    }
    if (node->name() == "update-player") {
        return readUpdatePlayer(node);
    }
    if (node->name() == "update-game-context") {
        return readUpdateGameContext(node);
    }
    if (node->name() == "set-players") {
        return readSetPlayers(node);
    }
    //[[[end]]]
    return GameEventCmdDataPtr();
}

/*[[[cog
for gec in GameEventCmds:
    cog.outl("void GameEventParser::write%(gameEventCmdName)s(QXmlStreamWriter* w, const %(structName)sPtr& gec)" % gec)
    cog.outl(gec.genWriter("w", "gec", True))
    cog.outl("%(structName)sPtr GameEventParser::read%(gameEventCmdName)s(XmlNode* n)" % gec)
    cog.outl(gec.genReader("n", None, True))
    cog.outl();
]]]*/
void GameEventParser::writeMoveCard(QXmlStreamWriter* w, const MoveCardCmdDataPtr& gec)
{
    w->writeStartElement("move-card");
    w->writeAttribute("pocket-type-from", toString(gec->pocketTypeFrom));
    w->writeAttribute("pocket-type-to", toString(gec->pocketTypeTo));
    w->writeAttribute("player-from", toString(gec->playerFrom));
    w->writeAttribute("player-to", toString(gec->playerTo));
    GameStructParser::write(w, gec->card, "card");
    GameStructParser::write(w, gec->secondCard, "second-card");
    w->writeEndElement();
}

MoveCardCmdDataPtr GameEventParser::readMoveCard(XmlNode* n)
{
    MoveCardCmdDataPtr res(new MoveCardCmdData());
    fromString(n->attribute("pocket-type-from"), res->pocketTypeFrom);
    fromString(n->attribute("pocket-type-to"), res->pocketTypeTo);
    fromString(n->attribute("player-from"), res->playerFrom);
    fromString(n->attribute("player-to"), res->playerTo);
    foreach (XmlNode* ch, n->getChildren()) {
        if (ch->name() == "card") {
            
            GameStructParser::read(ch, res->card);
            continue;
        }
        if (ch->name() == "second-card") {
            
            GameStructParser::read(ch, res->secondCard);
            continue;
        }
    }
    return res;
}

void GameEventParser::writeUpdatePlayer(QXmlStreamWriter* w, const UpdatePlayerCmdDataPtr& gec)
{
    w->writeStartElement("update-player");
    w->writeAttribute("player-id", toString(gec->playerId));
    if (gec->hasFlag(UpdatePlayerCmdData::IsAliveAttr)) {
         w->writeAttribute("is-alive", toString(gec->isAlive));
    }
    if (gec->hasFlag(UpdatePlayerCmdData::IsWinnerAttr)) {
         w->writeAttribute("is-winner", toString(gec->isWinner));
    }
    if (gec->hasFlag(UpdatePlayerCmdData::TakenCharacterAttr)) {
         w->writeAttribute("taken-character", toString(gec->takenCharacter));
    }
    if (gec->hasFlag(UpdatePlayerCmdData::LifePointsAttr)) {
         w->writeAttribute("life-points", toString(gec->lifePoints));
    }
    if (gec->hasFlag(UpdatePlayerCmdData::RoleAttr)) {
         w->writeAttribute("role", toString(gec->role));
    }
    w->writeEndElement();
}

UpdatePlayerCmdDataPtr GameEventParser::readUpdatePlayer(XmlNode* n)
{
    UpdatePlayerCmdDataPtr res(new UpdatePlayerCmdData());
    fromString(n->attribute("player-id"), res->playerId);
    if (n->hasAttribute("is-alive")) {
        res->setFlag(UpdatePlayerCmdData::IsAliveAttr);
        fromString(n->attribute("is-alive"), res->isAlive);
    }
    if (n->hasAttribute("is-winner")) {
        res->setFlag(UpdatePlayerCmdData::IsWinnerAttr);
        fromString(n->attribute("is-winner"), res->isWinner);
    }
    if (n->hasAttribute("taken-character")) {
        res->setFlag(UpdatePlayerCmdData::TakenCharacterAttr);
        fromString(n->attribute("taken-character"), res->takenCharacter);
    }
    if (n->hasAttribute("life-points")) {
        res->setFlag(UpdatePlayerCmdData::LifePointsAttr);
        fromString(n->attribute("life-points"), res->lifePoints);
    }
    if (n->hasAttribute("role")) {
        res->setFlag(UpdatePlayerCmdData::RoleAttr);
        fromString(n->attribute("role"), res->role);
    }
    return res;
}

void GameEventParser::writeUpdateGameContext(QXmlStreamWriter* w, const UpdateGameContextCmdDataPtr& gec)
{
    w->writeStartElement("update-game-context");
    GameStructParser::write(w, gec->gameContext, "game-context");
    w->writeEndElement();
}

UpdateGameContextCmdDataPtr GameEventParser::readUpdateGameContext(XmlNode* n)
{
    UpdateGameContextCmdDataPtr res(new UpdateGameContextCmdData());
    foreach (XmlNode* ch, n->getChildren()) {
        if (ch->name() == "game-context") {
            
            GameStructParser::read(ch, res->gameContext);
            continue;
        }
    }
    return res;
}

void GameEventParser::writeSetPlayers(QXmlStreamWriter* w, const SetPlayersCmdDataPtr& gec)
{
    w->writeStartElement("set-players");
    GameStructParser::write(w, gec->players, "players");
    w->writeEndElement();
}

SetPlayersCmdDataPtr GameEventParser::readSetPlayers(XmlNode* n)
{
    SetPlayersCmdDataPtr res(new SetPlayersCmdData());
    foreach (XmlNode* ch, n->getChildren()) {
        if (ch->name() == "players") {
            
            GameStructParser::read(ch, res->players);
            continue;
        }
    }
    return res;
}

//[[[end]]]